package com.smarthome.ipc.hk;

import java.util.HashMap;
import java.util.Map;

import javax.annotation.Resource;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.smarthome.common.ipc.Command;
import com.smarthome.common.tools.BossCachedKeysUtil;
import com.smarthome.common.tools.IPNetUtils;
import com.smarthome.common.tools.cache.JedisUtils;
import com.smarthome.domain.ipc.IpcCodeEnum;
import com.smarthome.domain.ipc.IpcConstants;
import com.smarthome.domain.ipc.IpcResponse;
import com.smarthome.domain.ipc.req.HkIpcResidenceDoorOpRequest;
import com.smarthome.domain.ipc.req.IpcLogRecordRequest;
import com.smarthome.ipc.IpcClientMain;
import com.smarthome.ipc.hk.demo.HCNetSDK;
import com.smarthome.ipc.hk.demo.HCNetSDK.NET_DVR_DEVICEINFO_V30;
import com.smarthome.ipc.hk.demo.HkClientService;
import com.smarthome.ipc.hk.entity.NetDvrLoginV30Entity;
import com.sun.jna.NativeLong;

/**
 * 海康门口机的主服务组件,主要完成小区内门禁机的管理功能。
 * 
 * @author denghw 2015/09/19 注：目前有基本思路，后续待持续完善。
 */
public abstract class HKMainService implements Command<HkIpcResidenceDoorOpRequest, IpcResponse<?>> {

	private static final Logger LOGGER = LoggerFactory.getLogger(HKMainService.class);
	private final static String PRE_LOGGER = "[HKMainService]";

	@Resource
	private HkClientService hkClientService;// 服务句柄

	protected static Map<String, Object> localCache = new HashMap<String, Object>();

	/**
	 * 回写异常信息到系统后台
	 * 
	 * @param sn
	 * @param cmd
	 * @param errCode
	 * @param errMsg
	 */
	protected void rtnBackErrMsg(String sn, String cmd, String errCode, String errMsg) {
		LOGGER.error(PRE_LOGGER + "海康门口机执行指令产生异常,错误代码为[" + errCode + "],错误信息为[" + errMsg + "].");
		IpcLogRecordRequest requestrtn = new IpcLogRecordRequest();
		requestrtn.setCommand(IpcConstants.IPC_COMMAND_LOG_RECORD);
		requestrtn.setCmd(cmd);
		requestrtn.setContent("海康门口机执行指令产生异常,错误代码为[" + errCode + "],错误信息为[" + errMsg + "].");
		requestrtn.setRemark("");
		requestrtn.setFailTimes(0);
		requestrtn.setSn(sn);
		requestrtn.setRtnCode(IpcCodeEnum.SYSTEM_ERROR.getCode());
		try {
			IpcClientMain.getInstance().sendCommand(requestrtn);
		} catch (Exception e1) {
			// TODO Auto-generated catch block
			LOGGER.info(PRE_LOGGER + "海康门口机执行指令产生异常后，向云平台推送错误日志产生异常！" + e1.getMessage());
		}

	}

	@Override
	public void execute(HkIpcResidenceDoorOpRequest request, IpcResponse<?> response) {
		// TODO Auto-generated method stub
		if (!IPNetUtils.isIpv4(request.getIp()) || !IPNetUtils.isPort(String.valueOf(request.getPort()))) {
			rtnBackErrMsg(request.getDeviceId(), request.getCommand(), IpcCodeEnum.PARM_NOT_VALID.getCode(),
					IpcCodeEnum.PARM_NOT_VALID.getMsg());
			response.setIpcCodeObj(IpcCodeEnum.PARM_NOT_VALID);
			return;
		}
		// 1.从缓存中获取操作句柄，
		NetDvrLoginV30Entity loginObj = (NetDvrLoginV30Entity) localCache.get(BossCachedKeysUtil
				.getKey(BossCachedKeysUtil.MODULE_HK_TALKDOOR_DEVICE, request.getIp() + request.getDeviceId()));
		if (loginObj == null || loginObj.getiUserId().longValue() < 0) {// 未登录设备
			// 注册之前先注销已注册的用户,预览情况下不可注销
			if (hkClientService.isbRealPlay()) {
				rtnBackErrMsg(request.getDeviceId(), request.getCommand(), null, "注册新用户请先停止当前预览!");
				return;
			}
			// 1.1若不存在则登录，
			NET_DVR_DEVICEINFO_V30 deviceObj = new HCNetSDK.NET_DVR_DEVICEINFO_V30();
			NativeLong lUserID = hkClientService.gethCNetSDK().NET_DVR_Login_V30(request.getIp(),
					(short) request.getPort(), request.getUserName(), request.getPsd(), deviceObj);
			if (lUserID.longValue() == -1) {
				if (hkClientService.gethCNetSDK().NET_DVR_GetLastError() == HCNetSDK.NET_DVR_NOINIT) {// 若登录失败的原因为未初始化
					if (hkClientService.hkinit()) {
						lUserID = hkClientService.gethCNetSDK().NET_DVR_Login_V30(request.getIp(),
								(short) request.getPort(), request.getUserName(), request.getPsd(), deviceObj);// 再次登录设备
					}
				}
			}
			// 如果仍然未登录成功
			if (lUserID.longValue() < 0) {
				JedisUtils.set(BossCachedKeysUtil.getKey(BossCachedKeysUtil.MODULE_HK_TALKDOOR_DEVICE,
						request.getIp() + request.getDeviceId()), null);
				rtnBackErrMsg(request.getDeviceId(), request.getCommand(),
						String.valueOf(hkClientService.gethCNetSDK().NET_DVR_GetLastError()), "登录门口机失败");
				return;
			}
			// 1.2，将相关操作句柄放入实例中，
			NetDvrLoginV30Entity loginObjnew = new NetDvrLoginV30Entity();
			loginObjnew.setiUserId(lUserID);
			loginObjnew.setDeviceInfo(deviceObj);
			loginObjnew.setUnicode(BossCachedKeysUtil.getKey(BossCachedKeysUtil.MODULE_HK_TALKDOOR_DEVICE,
					request.getIp() + request.getDeviceId()));
			loginObjnew.sethCNetSDK(hkClientService.gethCNetSDK());
			loginObjnew.setDeviceid(request.getDeviceId());
			// 1.3，初始化，
			loginObjnew.init();
			// 1.4，存入缓存，
			localCache.put(BossCachedKeysUtil.getKey(BossCachedKeysUtil.MODULE_HK_TALKDOOR_DEVICE,
					request.getIp() + request.getDeviceId()), loginObjnew);
			// 1.5，存入SDK操作句柄
			hkClientService.getlUserIDs().put(lUserID, null);
		}

		// 2.执行命令
		// 注:任何一个环节产生异常，均将异常返回云平台。
		doCmd(request, response);
	}

	protected abstract void doCmd(HkIpcResidenceDoorOpRequest request, IpcResponse<?> response);
}
